package com.runfast.paotui.service.impl;

import com.runfast.common.dao.model.*;
import com.runfast.common.exception.BaseException;
import com.runfast.common.security.spring.UserDataDetails;
import com.runfast.common.service.*;
import com.runfast.common.utils.DateUtils;
import com.runfast.common.utils.DistanceUtil;
import com.runfast.common.utils.GPSUtil;
import com.runfast.common.utils.GeoUtil;
import com.runfast.common.web.entity.Result;
import com.runfast.common.web.entity.ResultCode;
import com.runfast.paotui.dao.mapper.OrderMapper;
import com.runfast.paotui.dao.model.*;
import com.runfast.paotui.mq.AmqpClient;
import com.runfast.paotui.service.*;
import com.runfast.paotui.task.async.MessagePushTask;
import com.runfast.paotui.web.dto.OrderDto;
import com.runfast.pay.Channel;
import com.runfast.pay.service.PayService;
import com.runfast.waimai.dao.model.RunfastAccountrecord;
import com.runfast.waimai.service.RunfastAccountrecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.text.RandomStringGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.util.*;

@Slf4j
@Service
@Lazy(false)
public class OrderServiceImpl extends BaseService<Order, Integer, OrderExample> implements OrderService {

    @Autowired
    private RunfastDeliverCostService deliverCostService;

    @Autowired
    private RunfastCuseraddressService cuseraddressService;

    @Autowired
    private RunfastAgentbusinessService agentbusinessService;


    @Autowired
    private RunfastCuserService cuserService;


    @Autowired
    private OrderStatusHistoryService orderStatusHistoryService;


    @Autowired
    private MessagePushTask messagePushTask;

    @Autowired
    private RunfastShopperService shopperService;

    @Resource(name = "ptPayService")
    @Lazy
    private PayService payService;

    @Autowired
    private AmqpClient amqpClient;

    @Autowired
    private RunfastAccountrecordService accountrecordService;

    @Autowired
    private RefundService refundService;

    @Autowired
    private PaotuiCostService costService;

    @Autowired
    private PaotuiCostDistanceService costDistanceService;

    @Autowired
    private PaotuiCostTimeService costTimeService;

    @Autowired
    private PaotuiCostWeightService costWeightService;

    @Autowired
    private RunfastLoginRecordService loginRecordService;

    @Override
    public OrderMapper getMapper() {
        return (OrderMapper) super.getMapper();
    }

    @Override
    public Result confirm(Order order) {
        Validate.notNull(order);
        Validate.notNull(order.getCuserId(), "order.cuserId 不能为null");
        Order.Type orderType = order.getType();
        Validate.notNull(orderType, "order.type 不能为null");
        if (orderType == Order.Type.DAIGOU) {
            validate(order, Order.Daigou.class);
        }

        if (orderType == Order.Type.QUSONGJIAN) {
            validate(order, Order.Qusongjian.class);
        }

        Order.Type type = order.getType();
        Integer toId = order.getToId();
        if (toId == null) return Result.fail(ResultCode.FAIL, "请指定收货地址");
        RunfastCuseraddress toAddress = cuseraddressService.selectByPrimaryKey(toId);

        if (toAddress == null) return Result.fail(ResultCode.FAIL, "不存在收货地址");
        Double toLng = Double.valueOf(toAddress.getLongitude());
        Double toLat = Double.valueOf(toAddress.getLatitude());

        Result deliveryInfo = null;
        RunfastAgentbusiness agentNearBy = null;
        if (type == Order.Type.DAIGOU) {
            Order.FromType fromType = order.getFromType();
            if (fromType != null) {
                Double fromLng = null;
                Double fromLat = null;
                if (fromType == Order.FromType.SPECIFIED) { //指定地址

                    fromLng = order.getFromLng();
                    fromLat = order.getFromLat();
                } else { //就近购买
                    fromLng = order.getUserLng();
                    fromLat = order.getUserLat();
                }

                double[] fromTransformed = GPSUtil.gcj02_To_Bd09(fromLat, fromLng);  //高德转百度
                fromLng = fromTransformed[1];
                fromLat = fromTransformed[0];

                agentNearBy = agentbusinessService.getAgentNearByRange(fromLng, fromLat);

                if (agentNearBy != null) {

                    deliveryInfo = getDeliveryInfo(order, type, toLng, toLat, fromLng, fromLat, agentNearBy);
                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST, "附近没有骑手");
                }

            }

        } else { //取送件
            Integer fromId = order.getFromId();

            if (fromId != null) {
                RunfastCuseraddress fromAddress = cuseraddressService.selectByPrimaryKey(fromId);
                if (fromAddress == null) return Result.fail(ResultCode.FAIL, "不存在fromId对应的取货地址");
                Double fromLng = Double.valueOf(fromAddress.getLongitude());
                Double fromLat = Double.valueOf(fromAddress.getLatitude());

                agentNearBy = agentbusinessService.getAgentNearByRange(fromLng, fromLat);
                if (agentNearBy != null) {
                    deliveryInfo = getDeliveryInfo(order, type, toLng, toLat, fromLng, fromLat, agentNearBy);
                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST, "附近没有骑手");
                }
            }

        }

        if (!deliveryInfo.isSuccess()) return deliveryInfo;
        Map<String, Object> deliveryInfoData = (Map<String, Object>) deliveryInfo.getData();

        Integer deliveryFee = (Integer) deliveryInfoData.get("deliveryFee");
        order.setDeliveryCost(deliveryFee);

        Integer distance = (Integer) deliveryInfoData.get("distance");
        order.setDistance(distance);
        Integer deliveryDuration = (Integer) deliveryInfoData.get("deliveryDuration");
        order.setDeliveryDuration(deliveryDuration);

        Integer amountPayable = 0;
        Integer tip = order.getTip();
        tip = tip == null ? 0 : tip * 100;
        amountPayable = deliveryFee + tip;
        order.setAmountPayable(amountPayable);


        //存入登录来源
        RunfastLoginRecordExample loginRecordExample = new RunfastLoginRecordExample();
        loginRecordExample.or().andAccountTypeEqualTo(0).andAccountIdEqualTo(order.getCuserId()).andLogoutTimeIsNull();
        List<RunfastLoginRecord> recordList = loginRecordService.selectByExample(loginRecordExample);
        if(!recordList.isEmpty() && recordList!=null)
            order.setLoginOn(recordList.get(0).getLoginOn());

//        String orderNo = OrderUtil.generateOrderNo("p");

        /**
         * 生成随机订单号
         */
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        String dateFormated = format.format(new Date());

        String orderNOPrefix = "pt";
        char[][] randomRange = {{'0', '9'}};
        RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange(randomRange);
        RandomStringGenerator randomStringGenerator = builder.build();
        String generate = randomStringGenerator.generate(6);
        String orderNo = orderNOPrefix + dateFormated + generate;

        order.setOrderNo(orderNo);
        order.setStatus(Order.Status.CREATED);

        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        order.setAgentId(agentNearBy.getId());

        this.insertSelective(order);

        OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
        orderStatusHistory.setStatus(Order.Status.CREATED);
        orderStatusHistory.setOrderId(order.getId());
        orderStatusHistory.setCreateTime(new Date());
        orderStatusHistory.setUpdateTime(new Date());
        orderStatusHistoryService.insertSelective(orderStatusHistory);

//        messagePushTask.newOrderNotify(orderNo, agentNearBy.getId());

        /**
         * 发送消息
         *
         */
        amqpClient.publish(AmqpClient.PtBindingKey, order);
        return Result.ok("下单成功", order);

    }

    /**
     * @param driverId
     * @param orderId
     * @return
     */
    @Override
    public Result take(Integer driverId, Integer orderId) {
        Validate.notNull(driverId, "driverId 不能为null");
        Validate.notNull(orderId, "orderId 不能为null");

        Order order = this.selectByPrimaryKey(orderId);
        Validate.notNull(order, "不存在该订单");

        Order.Status status = order.getStatus();
        if (status != Order.Status.PAID) {
            return Result.fail(ResultCode.ILLEGAL_OPERATION, "非法操作，订单当前状态为已支付才能接单");
        }

        Integer agentId = order.getAgentId();

        RunfastAgentbusiness agentbusiness = agentbusinessService.selectByPrimaryKey(agentId);
        BigDecimal agentbusinessCoefficient = agentbusiness.getCoefficient();


        RunfastShopper shopper = shopperService.selectByPrimaryKey(driverId);
        BigDecimal shopperCoefficient = shopper.getCoefficient();


        if (agentbusinessCoefficient != null && shopperCoefficient != null && shopperCoefficient.subtract(agentbusinessCoefficient).doubleValue() >= 0) {

            int plateformIncome = agentbusinessCoefficient.multiply(BigDecimal.valueOf(order.getAmountPaid())).intValue();

            int agentIncome = shopperCoefficient.multiply(BigDecimal.valueOf(order.getAmountPaid())).subtract(BigDecimal.valueOf(plateformIncome)).intValue();

            int driverIncome = order.getAmountPaid() - plateformIncome - agentIncome;

            OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
            orderStatusHistory.setStatus(Order.Status.TAKEN);
            orderStatusHistory.setOrderId(order.getId());
            orderStatusHistory.setCreateTime(new Date());
            orderStatusHistory.setUpdateTime(new Date());
            orderStatusHistoryService.insertSelective(orderStatusHistory);

            Order orderUpdate = new Order();
            orderUpdate.setStatus(Order.Status.TAKEN);
            orderUpdate.setTaken(true);
            orderUpdate.setTimeTaken(new Date());
            orderUpdate.setDriverId(driverId);
            orderUpdate.setDriverIncome(driverIncome);
            orderUpdate.setAgentIncome(agentIncome);
            orderUpdate.setPlateformIncome(plateformIncome);
            orderUpdate.setUpdateTime(new Date());

            OrderExample orderExample = new OrderExample();
            orderExample.createCriteria().andIdEqualTo(orderId)
                    .andStatusEqualTo(Order.Status.PAID.ordinal());
            int count = this.updateByExampleSelective(orderUpdate, orderExample);
            if (count == 1) {

//                messagePushTask.takenOrderNotity(order.getOrderNo(), order.getCuserId());

                return Result.ok("接单成功");
            } else {
                return Result.fail(ResultCode.FAIL, "没有可处理的订单");
            }

        } else {
            return Result.fail(ResultCode.PARAMETER_ERROR, "agentbusiness.coefficient和shopper.coefficient不能为null，且shopper.coefficient必须大于等于agentbusiness.coefficient");
        }


    }

    @Override
    public Result cancel(Integer userId, Integer orderId) {

        Validate.notNull(userId, "userId 不能为null");
        Validate.notNull(orderId, "orderId 不能为null");

        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andCuserIdEqualTo(userId)
                .andIdEqualTo(orderId);

        List<Order> orders = this.selectByExample(orderExample);
        if (orders.isEmpty()) return Result.fail(ResultCode.FAIL, "该用户下不存在要取消的订单");

        Order order = orders.get(0);
        Order.Status status = order.getStatus();
        if (status == Order.Status.CREATED || status == Order.Status.PAID) {

            OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
            orderStatusHistory.setStatus(Order.Status.CANCELED);
            orderStatusHistory.setOrderId(order.getId());
            orderStatusHistory.setCreateTime(new Date());
            orderStatusHistory.setUpdateTime(new Date());
            orderStatusHistoryService.insertSelective(orderStatusHistory);


            Order orderUpdate = new Order();
            orderUpdate.setId(orderId);
            orderUpdate.setStatus(Order.Status.CANCELED);
            orderUpdate.setCanceled(true);
            orderUpdate.setTimeCanceled(new Date());
            orderUpdate.setUpdateTime(new Date());


            this.updateByPrimaryKeySelective(orderUpdate);

            if (status == Order.Status.PAID) {

                Result result = payService.refund(order.getOrderNo(), UUID.randomUUID().toString(), order.getAmountPaid(), "自动退款");
                if (result.isSuccess()) {
                    /**
                     * 发送消息
                     *
                     */
                    amqpClient.publish(AmqpClient.PtBindingKey, this.selectByPrimaryKey(orderId));
                    return Result.ok("您的退款已退回您的支付账号，请留意");
                } else {
                    throw new BaseException(ResultCode.FAIL, "取消订单失败,原因：" + result.getErrorMsg());//回滚事务
                }
            } else {
                return Result.ok("取消订单成功");
            }


        } else {
            return Result.fail(ResultCode.FAIL, "骑手已接单，只能取消还未处理的订单");
        }


    }

    @Override
    public List<Map<String, Integer>> selectIdUserIdByExample(OrderExample example) {
        return mapper.selectIdUserIdByExample(example);
    }

    @Override
    public Result fillIn(Order order) {
        Validate.notNull(order, "order 不能为null");
        Validate.notNull(order.getUserLng(), "order.userLng 不能为null");
        Validate.notNull(order.getUserLat(), "order.userLat 不能为null");


        Order.Type type = order.getType();
        if (type == null) return Result.fail(ResultCode.FAIL, "请指定是代购还是取送件");
        Integer toId = order.getToId();

        if (toId == null) {
            if (type == Order.Type.DAIGOU) {
                Order.FromType fromType = order.getFromType();
                if (fromType == null) return Result.fail(ResultCode.FAIL, "请指定代购取货的地址类型");
                Double fromLng = null;
                Double fromLat = null;
                if (fromType == Order.FromType.SPECIFIED) { //指定地址

                    fromLng = order.getFromLng();
                    fromLat = order.getFromLat();
                } else { //就近购买
                    fromLng = order.getUserLng();
                    fromLat = order.getUserLat();
                }

                double[] fromTransformed = GPSUtil.gcj02_To_Bd09(fromLat, fromLng);  //高德转百度
                fromLng = fromTransformed[1];
                fromLat = fromTransformed[0];

                RunfastAgentbusiness agentNearBy = agentbusinessService.getAgentNearByRange(fromLng, fromLat);

                if (agentNearBy != null) {
                    return Result.ok("");

                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST, "附近没有骑手");
                }


            } else { //取送件
                Integer fromId = order.getFromId();
                if (fromId == null) return Result.fail(ResultCode.FAIL, "请指定取送件的取货地址");

                RunfastCuseraddress fromAddress = cuseraddressService.selectByPrimaryKey(fromId);
                if (fromAddress == null) return Result.fail(ResultCode.FAIL, "不存在的取货地址");
                Double fromLng = Double.valueOf(fromAddress.getLongitude());
                Double fromLat = Double.valueOf(fromAddress.getLatitude());


                RunfastAgentbusiness agentNearBy = agentbusinessService.getAgentNearByRange(fromLng, fromLat);
                if (agentNearBy != null) {
                    return Result.ok("");
                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST, "附近没有骑手");
                }

            }

        } else {
            RunfastCuseraddress toAddress = cuseraddressService.selectByPrimaryKey(toId);

            if (toAddress == null) return Result.fail(ResultCode.FAIL, "不存在收货地址");
            Double toLng = Double.valueOf(toAddress.getLongitude());
            Double toLat = Double.valueOf(toAddress.getLatitude());

            if (type == Order.Type.DAIGOU) {
                Order.FromType fromType = order.getFromType();
                if (fromType == null) return Result.fail(ResultCode.FAIL, "请指定代购取货的地址类型");
                Double fromLng = null;
                Double fromLat = null;
                if (fromType == Order.FromType.SPECIFIED) { //指定地址

                    fromLng = order.getFromLng();
                    fromLat = order.getFromLat();
                } else { //就近购买
                    fromLng = order.getUserLng();
                    fromLat = order.getUserLat();
                }

                double[] fromTransformed = GPSUtil.gcj02_To_Bd09(fromLat, fromLng);  //高德转百度
                fromLng = fromTransformed[1];
                fromLat = fromTransformed[0];

                RunfastAgentbusiness agentNearBy = agentbusinessService.getAgentNearByRange(fromLng, fromLat);

                if (agentNearBy != null) {

                    return getDeliveryInfo(order, type, toLng, toLat, fromLng, fromLat, agentNearBy);
                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST, "附近没有骑手");
                }


            } else { //取送件
                Integer fromId = order.getFromId();
                if (fromId == null) return Result.fail(ResultCode.FAIL, "请指定取送件的取货地址");

                RunfastCuseraddress fromAddress = cuseraddressService.selectByPrimaryKey(fromId);
                if (fromAddress == null) return Result.fail(ResultCode.FAIL, "不存在的取货地址");
                Double fromLng = Double.valueOf(fromAddress.getLongitude());
                Double fromLat = Double.valueOf(fromAddress.getLatitude());


                RunfastAgentbusiness agentNearBy = agentbusinessService.getAgentNearByRange(fromLng, fromLat);
                if (agentNearBy != null) {
                    return getDeliveryInfo(order, type, toLng, toLat, fromLng, fromLat, agentNearBy);
                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST, "附近没有骑手");
                }

            }
        }


    }

    private Result getDeliveryInfo(Order order, Order.Type type, Double toLng, Double toLat, Double fromLng, Double fromLat, RunfastAgentbusiness agentNearBy) {
        Map<String, Object> data = new HashMap<>();
        PaotuiCost defaultCost = costService.getDefaultCost(agentNearBy.getId());
        if (defaultCost == null) return Result.fail(ResultCode.FAIL, "代理商未设置跑腿配送模板");
        Integer costId = defaultCost.getId();
        Double distance = DistanceUtil.getDistanceBy(fromLng, fromLat, toLng, toLat) / 1000d;

        PaotuiCostDistanceExample costDistanceExample = new PaotuiCostDistanceExample();
        costDistanceExample.or().andCostidEqualTo(costId);
        List<PaotuiCostDistance> costDistanceList = costDistanceService.selectByExample(costDistanceExample);
        Double maxDis = 0d;
        for (PaotuiCostDistance costDistance : costDistanceList) {
            Double enddistance = costDistance.getEnddistance();
            maxDis = enddistance > maxDis ? enddistance : maxDis;
        }

        if (distance > maxDis) return Result.fail(ResultCode.FAIL, "超出配送距离");


        RunfastDeliverCost defaultDeliveryTemplate = deliverCostService.getDefaultDeliveryTemplate(agentNearBy.getId());

        if (defaultDeliveryTemplate == null) return Result.fail(ResultCode.FAIL, "代理商未设置外卖配送模板");
        /**
         * 是否超出配送距离
         */


        Double maxDistance = defaultDeliveryTemplate.getMaxDistance();//以公里为单位
        String distRange = defaultDeliveryTemplate.getDistRange();

        if (maxDistance != null) {
            if (distance > maxDistance) {

                return Result.fail(ResultCode.FAIL, "超出配送距离");
            }

        } else if (StringUtils.isNotBlank(distRange)) {

            Point2D.Double piont = new Point2D.Double(toLng, toLat);

            List<Point2D.Double> psList = new ArrayList<Point2D.Double>();
            String ps[] = distRange.split("\\|");

            for (String p : ps) {
                if (StringUtils.isNotBlank(p)) {
                    String xs[] = p.split(",");
                    if (xs.length > 1) {
                        Point2D.Double p2d = new Point2D.Double(Double.parseDouble(xs[1]), Double.parseDouble(xs[0]));
                        psList.add(p2d);
                    }
                }

            }

            if (!GeoUtil.IsPtInPoly(piont, psList))
                return Result.fail(ResultCode.FAIL, "超出配送范围");
        }


        Integer basictime = defaultCost.getBasictime();
        Double basedistance = defaultCost.getBasedistance();
        BigDecimal daigoubasecost = defaultCost.getDaigoubasecost();
        BigDecimal qusongjianbasecost = defaultCost.getQusongjianbasecost();

        Double overtimedistance = defaultCost.getOvertimedistance();
        Integer overtimetime = defaultCost.getOvertimetime();

        Integer duration = 25;
        Integer baseFee = type == Order.Type.DAIGOU ? daigoubasecost.multiply(BigDecimal.valueOf(100)).intValue() : qusongjianbasecost.multiply(BigDecimal.valueOf(100)).intValue();

        Integer exceedFee = null;

        Integer weightFee = null;

        Integer deliveryFee = 0;

        /**
         * 配送时间
         */
        PaotuiCostTimeExample costTimeExample = new PaotuiCostTimeExample();
        costTimeExample.or().andCostidEqualTo(costId);

        List<PaotuiCostTime> paotuiCostTimes = costTimeService.selectByExample(costTimeExample);
        LocalTime now = DateUtils.localTime(new Date());
        Integer timeFee = 0; //时段附加费
        for (PaotuiCostTime costTime : paotuiCostTimes) {
            LocalTime start = DateUtils.localTime(costTime.getStarttime());
            LocalTime end = DateUtils.localTime(costTime.getEndtime());

            if (now.isAfter(start) && now.isBefore(end)) {
                timeFee = costTime.getFee().multiply(BigDecimal.valueOf(100)).intValue();
                break;
            }
        }
        if (distance <= basedistance) {
            duration = basictime;
        } else {
            double v = distance - basedistance;
            Double v1 = Math.ceil(v * overtimetime / overtimedistance);
            duration = basictime + v1.intValue();

            for (PaotuiCostDistance costDistance : costDistanceList) {
                Double startdistance = costDistance.getStartdistance();
                Double enddistance = costDistance.getEnddistance();
                BigDecimal fee = costDistance.getFee();
                if (v > startdistance && v <= enddistance) {
                    exceedFee = fee.multiply(BigDecimal.valueOf(100)).intValue();
                    break;
                }
            }

            if (exceedFee == null) return Result.fail(ResultCode.FAIL, "距离超出了配送范围");
        }

        if (type == Order.Type.QUSONGJIAN) {
            PaotuiCostWeightExample costWeightExample = new PaotuiCostWeightExample();
            costWeightExample.or().andCostidEqualTo(costId);
            List<PaotuiCostWeight> costWeightList = costWeightService.selectByExample(costWeightExample);
            Integer weight = order.getGoodsWeight();

            for (PaotuiCostWeight costWeight : costWeightList) {
                Double startweight = costWeight.getStartweight();
                Double endweight = costWeight.getEndweight();
                BigDecimal fee = costWeight.getFee();
                if (weight > startweight && weight <= endweight) {
                    weightFee = fee.multiply(BigDecimal.valueOf(100)).intValue();
                    break;
                }

            }
            if (weightFee == null) return Result.fail(ResultCode.FAIL, "重量超出了配送限制");
        }


        data.put("distance", (int) (distance * 1000));
        data.put("deliveryDuration", duration < 25 ? 25 : duration);
        data.put("baseFee", baseFee);
        data.put("exceedFee", exceedFee);
        data.put("weightFee", weightFee);
        data.put("timeFee", timeFee);
        data.put("deliveryFee", baseFee + (exceedFee == null ? 0 : exceedFee) + (weightFee == null ? 0 : weightFee) + timeFee);


        return Result.ok("", data);
    }

    @Override
    public OrderDto toOrderDto(Order order) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        OrderDto orderDto = new OrderDto();
        Order.Type type = order.getType();

        PropertyUtils.copyProperties(orderDto, order);
        Integer driverId = order.getDriverId();
        if (driverId != null) {
            RunfastShopper runfastShopper = shopperService.selectByPrimaryKey(driverId);
            if (runfastShopper != null) {
                orderDto.setDriverName(runfastShopper.getName());
                orderDto.setDriverMobile(runfastShopper.getMunber());
            }


        }

        switch (type) {
            case DAIGOU:
                Order.FromType fromType = order.getFromType();
                if (fromType == Order.FromType.NEARBY) {
                    orderDto.setFromAddress("就近购买");
                }
                break;
            case QUSONGJIAN:
                Integer fromId = order.getFromId();

                RunfastCuseraddress runfastCuseraddress = cuseraddressService.selectByPrimaryKey(fromId);
                orderDto.setFromAddress(runfastCuseraddress.getUserAddress() + runfastCuseraddress.getAddress());
                orderDto.setFromName(runfastCuseraddress.getName());
                orderDto.setFromMobile(runfastCuseraddress.getPhone());
                break;
        }

        Integer toId = order.getToId();

        RunfastCuseraddress runfastCuseraddress = cuseraddressService.selectByPrimaryKey(toId);
        orderDto.setToAddress(runfastCuseraddress.getUserAddress() + runfastCuseraddress.getAddress());
        orderDto.setToName(runfastCuseraddress.getName());
        orderDto.setToMobile(runfastCuseraddress.getPhone());

        return orderDto;
    }

    @Override
    public void complete(Integer userId, Integer id) {
        OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
        orderStatusHistory.setStatus(Order.Status.COMPLETED);
        orderStatusHistory.setOrderId(id);
        orderStatusHistory.setCreateTime(new Date());
        orderStatusHistory.setUpdateTime(new Date());
        orderStatusHistoryService.insertSelective(orderStatusHistory);

        Order orderUpdate = new Order();
        orderUpdate.setId(id);
        orderUpdate.setStatus(Order.Status.COMPLETED);
        orderUpdate.setCompleted(true);
        orderUpdate.setTimeCompleted(new Date());
        this.updateByPrimaryKeySelective(orderUpdate);

        Order order = this.selectByPrimaryKey(id);
        /**
         * 发送消息
         *
         */
        amqpClient.publish(AmqpClient.PtBindingKey, order);
    }

    @Override
    public Result walletPay(Integer orderId, String password) {
        Order order = this.selectByPrimaryKey(orderId);
        if (order == null) return Result.fail(ResultCode.FAIL, "该订单不存在");

        UserDataDetails<RunfastCuser> principal = (UserDataDetails<RunfastCuser>) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        RunfastCuser cuser = principal.getData();

        if (!cuser.getPassword().equals(password)) return Result.fail(ResultCode.FAIL, "支付密码不正确");

        Order.Status status = order.getStatus();
        if (status != Order.Status.CREATED) return Result.fail(ResultCode.FAIL, "新下的订单才能支付");
        BigDecimal decimalAmountPaid = BigDecimal.valueOf(order.getAmountPayable()).divide(BigDecimal.valueOf(100), 2);
        BigDecimal remainder = cuser.getRemainder();
        remainder = remainder == null ? BigDecimal.valueOf(0) : remainder;

        BigDecimal totalremainder = cuser.getTotalremainder();
        if (totalremainder == null || totalremainder.compareTo(remainder) == -1) totalremainder = remainder;

        if (remainder.compareTo(decimalAmountPaid) == -1) return Result.fail(ResultCode.FAIL, "用户可用余额不足");

        /**
         * 更新用户余额
         */
        RunfastCuser cuserUpdate = new RunfastCuser();
        cuserUpdate.setId(cuser.getId());
        cuserUpdate.setRemainder(remainder.subtract(decimalAmountPaid));


        cuserUpdate.setTotalremainder(totalremainder.subtract(decimalAmountPaid));

        cuserService.updateByPrimaryKeySelective(cuserUpdate);

        /**
         * 账户变动清单
         */
        RunfastAccountrecord ar = new RunfastAccountrecord();
        ar.setBeforemonety(cuser.getRemainder());

        ar.setBalance(remainder);
        ar.setCardnumber(order.getOrderNo());
        ar.setCid(cuser.getId());
        ar.setShowtype(1);
        ar.setMonetary(BigDecimal.ZERO.subtract(decimalAmountPaid));
        ar.setCreateTime(new Date());
        ar.setType(0);
        ar.setTypename("消费");
        ar.setMobile(cuser.getMobile());
        ar.setName(cuser.getName());

        accountrecordService.insertSelective(ar);


        /**
         * 更新订单
         */
        Order orderUpdated = new Order();
        orderUpdated.setId(order.getId());
        orderUpdated.setChannel(Channel.BALANCE);
        orderUpdated.setAmountPaid(order.getAmountPayable());
        orderUpdated.setPaid(true);
        orderUpdated.setStatus(Order.Status.PAID);
        orderUpdated.setTimePaid(new Date());

        this.updateByPrimaryKeySelective(orderUpdated);

        OrderStatusHistory orderStatusHistoryAdded = new OrderStatusHistory();
        orderStatusHistoryAdded.withOrderId(order.getId())
                .withCreateTime(new Date())
                .withUpdateTime(new Date())
                .withStatus(Order.Status.PAID);
        orderStatusHistoryService.insertSelective(orderStatusHistoryAdded);

        //用户下单通知
        messagePushTask.newOrderNotify(order.getOrderNo(), order.getAgentId());


        /**
         * 发送消息
         *
         */
        amqpClient.publish(AmqpClient.PtBindingKey, this.selectByPrimaryKey(orderId));
        return Result.ok("");
    }

    @Override
    public Result applyCancel(Integer userId, Integer orderId) {
        Validate.notNull(userId, "userId 不能为null");
        Validate.notNull(orderId, "orderId 不能为null");

        RunfastCuser cuser = cuserService.selectByPrimaryKey(userId);

        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andCuserIdEqualTo(userId)
                .andIdEqualTo(orderId);

        List<Order> orders = this.selectByExample(orderExample);
        if (orders.isEmpty()) return Result.fail(ResultCode.FAIL, "该用户下不存在该订单");

        Order order = orders.get(0);
        Order.Status status = order.getStatus();
        //订单状态 CREATED（已下单）, CANCELED（已取消）, PAID（已支付）, TAKEN（已接单）, COMPLETED（已完成）,PICKED（已取货）

        switch (status) {
            case CREATED:
            case PAID:
                return cancel(userId, orderId);
            case TAKEN:
            case PICKED: {
                Integer isCancel = order.getIsCancel();
                if (isCancel != null && isCancel == 1) return Result.fail(ResultCode.FAIL, "订单已经申请取消，请等待骑手确认");

                Refund refund = new Refund();
                refund.setStatus(Refund.Status.PENDING);
                refund.setAmount(order.getAmountPaid());
                refund.setChargeOrderNo(UUID.randomUUID().toString());
                refund.setOrderNo(order.getOrderNo());
                refund.setOrderId(order.getId());
                refund.setCreateTime(new Date());
                refund.setDescription("骑手已接单，用户申请取消");
                refund.setUpdateTime(new Date());

                refundService.insertSelective(refund);

                /**
                 * 更新订单
                 */
                Order orderUpdate = new Order();
                orderUpdate.setId(order.getId());
                orderUpdate.setIsCancel(1);
                orderUpdate.setCancelTime(new Date());

                this.updateByPrimaryKeySelective(orderUpdate);


                messagePushTask.applyCancelOrderNotify(this.selectByPrimaryKey(orderId));//发生申请取消订单的通知

                return Result.ok("");
            }
            case COMPLETED:
                return Result.fail(ResultCode.FAIL, "订单已经完成");
            case CANCELED:
                return Result.fail(ResultCode.FAIL, "订单已经取消");


        }
        return Result.fail(ResultCode.FAIL, "非法的订单状态");

    }

    @Override
    public List<Map<String, Integer>> findConfirmCancelOrder(Date time) {
        return getMapper().findConfirmCancelOrder(time);
    }

    @Override
    public void confirmCancel(Integer userId, Integer orderId) {
        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andCuserIdEqualTo(userId)
                .andIdEqualTo(orderId);

        List<Order> orders = this.selectByExample(orderExample);
        if (orders.isEmpty()) return;

        Order order = orders.get(0);
        Boolean paid = order.getPaid();
        if (paid != null && paid) {

            OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
            orderStatusHistory.setStatus(Order.Status.CANCELED);
            orderStatusHistory.setOrderId(order.getId());
            orderStatusHistory.setCreateTime(new Date());
            orderStatusHistory.setUpdateTime(new Date());
            orderStatusHistoryService.insertSelective(orderStatusHistory);


            Order orderUpdate = new Order();
            orderUpdate.setId(orderId);
            orderUpdate.setStatus(Order.Status.CANCELED);
            orderUpdate.setCanceled(true);
            orderUpdate.setTimeCanceled(new Date());
            orderUpdate.setUpdateTime(new Date());
            orderUpdate.setIsCancel(4);


            this.updateByPrimaryKeySelective(orderUpdate);


            Result result = payService.refund(order.getOrderNo(), UUID.randomUUID().toString(), order.getAmountPaid(), "自动退款");
            if (result.isSuccess()) {
                /**
                 * 发送消息
                 *
                 */
                amqpClient.publish(AmqpClient.PtBindingKey, this.selectByPrimaryKey(orderId));
            } else {
                throw new BaseException(ResultCode.FAIL, "取消订单失败,原因：" + result.getErrorMsg());//回滚事务
            }

        }
    }

}